<template>
  <div
    class="fdx-pull-to-refresh"
    :class="[tip?'fdx-pull-to-refresh--tip':'','fdx-pull-to-refresh--'+type]" ref="pullToRefresh">
    <div v-show="list.length">
      <tip
        :num="total"
        v-if="tip"
        @close="closeTip"
        ref="tip"
        :prefix="tipPrefix"
        :unit="tipUnit"></tip>
      <scroller
        ref="scroller"
        :on-refresh="refresh"
        :on-infinite="infinite"
        :no-data-text="noDataText"
        :class="closeTipAnimation"
        v-show="isShow"
        :min-content-height="-1"
        v-if="pulldown">
        <slot></slot>
      </scroller>
      <scroller
        ref="scroller"
        :on-infinite="infinite"
        :no-data-text="noDataText"
        :class="closeTipAnimation"
        v-show="isShow"
        :min-content-height="-1"
        v-else>
        <slot></slot>
      </scroller>
    </div>
    <scroller v-if="allLoaded && list.length === 0">
      <no-result
        :title="noResultText"
        :clear="clearFilter"
        @clear="clear"
        v-if="!$slots.noResult"></no-result>
      <slot name="noResult"></slot>
    </scroller>
    <loading v-show="!allLoaded && url && list.length === 0" text=""></loading>
  </div>
</template>

<script>
import NoResult from 'base/no-result/no-result'
import tip from 'base/result-tip/result-tip'
import Loading from 'base/loading/loading'
import fetch from 'assets/js/fetch'
import { AJAX_SERVICE_HOST } from 'api/config'
export default {
  name: 'PullToRefresh',
  components: {
    tip,
    NoResult,
    Loading
  },
  props: {
    tip: {
      type: Boolean,
      default: false
    },
    url: {
      type: String,
      default: ''
    },
    type: {
      type: String,
      default: 'gap' // gap两边有间隔,fluid占满整屏
    },
    params: {
      type: Object,
      default: function() {
        return {}
      }
    },
    noResultText: String,
    clearFilter: {
      type: Boolean,
      default: false
    },
    pulldown: {
      type: Boolean,
      default: true
    },
    value: {
      type: Array,
      default: function() {
        return []
      }
    },
    loading: {
      type: Boolean,
      default: true
    },
    auto: {
      type: Boolean, // 是否自动加载一次
      default: true
    },
    enable: {
      type: Boolean, //  是否有效
      default: true
    },
    relateRole: {
      type: Boolean,
      default: true
    },
    noMoreDataText: {
      type: String,
      default: '没有更多数据'
    },
    tipUnit: {
      type: String,
      default: null
    },
    tipPrefix: {
      type: String,
      default: '为您找到'
    },
    autoHideNoDataTip: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      isShow: false,
      allLoaded: false,
      closeTipAnimation: '',
      noDataText: this.noMoreDataText,
      pageConfig: {
        page: 1,
        rows: 10
      },
      list: this.value || [],
      total: '',
      refreshing: false,
      isChanged: true
    }
  },
  computed: {
    path: function() {
      const url = this.url
      return AJAX_SERVICE_HOST + url
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.isShow = true
      this.getListData()
    })
  },
  methods: {
    clear() {
      this.$emit('clear')
    },
    showTip() {
      this.$refs.tip && this.$refs.tip.show()
      this.closeTipAnimation = ''
    },
    closeTip() {
      this.closeTipAnimation = 'close-tip-animation'
    },
    scrollToTop() {
      this.scrollTo(0, 0, false)
    },
    scrollTo(x, y, animate) {
      this.$refs.scroller.scrollTo(x, y, animate)
    },
    async moreListData(done) {
      if (!this.enable) {
        done(true)
        return
      }
      this.isChanged = false
      this.pageConfig.page++
      this.noDataText = this.noMoreDataText
      try {
        var res = await fetch.get(this.path, {
          ...this.pageConfig,
          ...this.params
        })
        if (res) {
          if (res.list) {
            this.list = this.list.concat(res.list || [])
            this.hasMore(this.list.length < res.total, done)
          } else {
            this.list = res.IsArray ? res : []
            this.hasMore(false)
          }
        } else {
          this.list = []
          this.hasMore(false)
        }
      } catch (ex) {
        this.list = []
        this.hasMore(false)
      }
    },
    hasMore(hasMore, done) {
      if (this.autoHideNoDataTip && !hasMore) {
        setTimeout(() => {
          this.noDataText = ''
        }, 3000)
      }
      this.allLoaded = !hasMore
      done && done(!hasMore)
    },
    async refresh(done) {
      this.refreshing = true
      this.showTip()
      await this.getListData(done || this.$refs.scroller.finishPullToRefresh)
      this.$emit('showTip', true)
      this.scrollToTop()
    },
    infinite(done) {
      if (this.allLoaded) {
        done(true)
        return
      }
      this.moreListData(done || this.$refs.scroller.finishInfinite)
    },
    async getListData(done) {
      done = done || this.$refs.scroller.finishInfinite
      if (!this.enable || !this.url) {
        done(true)
        this.allLoaded = true
        return
      }
      this.isChanged = false
      this.pageConfig.page = 1
      this.noDataText = this.noMoreDataText
      try {
        var res = await fetch.get(this.path, {
          ...this.pageConfig,
          ...this.params
        })
        Indicator.close()
        if (res) {
          if (res.extra) {
            this.$emit('getExtra', res.extra)
          }
          if (res.list) {
            this.list = res.list || []
            this.total = res.total
            this.hasMore(this.list.length < res.total, done)
          } else {
            this.list = res.IsArray ? res : []
            this.hasMore(false)
          }
        } else {
          this.list = []
          this.hasMore(false)
        }
        this.$emit('load', res)
        if (this.refreshing) this.refreshing = false
      } catch (ex) {
        Indicator.close()
        this.list = []
        this.hasMore(false)
      }
    },
    getScrollPos() {
      return this.$refs.scroller.getPosition()
    }
  },
  watch: {
    value(newVal) {
      this.list = newVal
    },
    list(newList) {
      this.$emit('input', newList)
    },
    params: {
      deep: true,
      handler(newVal, oldVal) {
        if (this.refreshing) return
        this.isChanged = true
        this.refresh()
      }
    },
    url() {
      this.isChanged = true
    },
    refreshing(newRefreshing) {
      if (!this.tip) return
      if (newRefreshing) {
        this.$refs.tip.clearTimer()
      } else {
        this.$refs.tip.setTimer()
      }
    },
    enable(newStatus) {
      if (newStatus && this.isChanged) {
        //  从无效变为有效且params或url发生了变化时，刷新数据
        this.refresh()
      }
    }
  }
}
</script>

<style lang="scss">
.fdx-pull-to-refresh {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  .fdx-tip {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    // z-index: 1000;
  }

  ._v-container {
    transition: all 0.4s;
  }
}

.fdx-pull-to-refresh--tip {
  ._v-container {
    top: 50px;
  }

  .close-tip-animation {
    top: 12px;
  }
}

.fdx-pull-to-refresh--fluid {
  ._v-container {
    padding: 0;
  }
}
</style>
